﻿// -----------------------------------------------------------------------
//    This file is part of TSGE.
//
//    TSGE is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 2 of the License, or
//    (at your option) any later version.
//
//    TSGE is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with TSGE.  If not, see <http://www.gnu.org/licenses/>.
// -----------------------------------------------------------------------

namespace tsge
{
    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Navigation;
    using System.Xml.Serialization;
    using tsge.Classes;
    using System.Reflection;

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// 
    ///     Inherits:
    ///         - Window
    /// </summary>
    public partial class MainWindow : Window
    {
        /// <summary>
        /// Internal copy of the player object bound to the editor.
        /// </summary>
        private Player m_vCurrentPlayer = null;

        /// <summary>
        /// Default Constructor
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();

            // Update the version strings..
            var asm = Assembly.GetExecutingAssembly();
            this.Title = "TSGE - Terraria Save Game Editor - v" + asm.GetName().Version;
            this.lblAboutVersion.Content = "Version: v" + asm.GetName().Version;

            // Load buff list..
            using (FileStream fStream = new FileStream("Data\\_bufflist.xml", FileMode.Open, FileAccess.Read))
            {
                XmlSerializer xls = new XmlSerializer(typeof(Buff[]));
                Terraria.Instance.Buffs = ((Buff[])xls.Deserialize(fStream)).ToList();
            }

            // Load item list..
            using (FileStream fStream = new FileStream("Data\\_itemlist.xml", FileMode.Open, FileAccess.Read))
            {
                XmlSerializer xls = new XmlSerializer(typeof(Item[]));
                Terraria.Instance.Items = ((Item[])xls.Deserialize(fStream)).ToList();
            }

            // Load item prefix list..
            using (FileStream fStream = new FileStream("Data\\_prefixlist.xml", FileMode.Open, FileAccess.Read))
            {
                XmlSerializer xls = new XmlSerializer(typeof(ItemPrefix[]));
                Terraria.Instance.Prefixes = ((ItemPrefix[])xls.Deserialize(fStream)).ToList();
            }

            // Load hair file list..
            dynamic hairList = this.Resources["terrHairList"];
            hairList.Path = AppDomain.CurrentDomain.BaseDirectory + "\\Data\\Hair\\";

            // Set context to new player instance..
            this.CurrentPlayer = new Player();

            // Set data sources for various lists..
            this.ceMainEditor.lstBuffList.ItemsSource = Terraria.Instance.Buffs;
            this.ceMainEditor.cboInventoryItem.ItemsSource = Terraria.Instance.Items;
            this.ceMainEditor.cboInventoryPrefix.ItemsSource = Terraria.Instance.Prefixes;
            this.ceMainEditor.cboEquipmentPrefixList.ItemsSource = Terraria.Instance.Prefixes;
            this.ceMainEditor.lstBankItemList.ItemsSource = Terraria.Instance.Items;
            this.ceMainEditor.cboBankItemPrefixList.ItemsSource = Terraria.Instance.Prefixes;

            // Attach random hair click event..
            this.ceMainEditor.btnRandomHair.Click += new RoutedEventHandler((sender, e) =>
            {
                Random r = new Random((int)DateTime.Now.Ticks);
                this.CurrentPlayer.Hair = r.Next(35);
                this.ceMainEditor.modelViewer.HairFile = String.Format("Data\\Hair\\hair_{0}.png", this.CurrentPlayer.Hair);
            });

            // Attach random colors click event..
            this.ceMainEditor.btnRandomColors.Click += new RoutedEventHandler((sender, e) =>
            {
                Random r = new Random((int)DateTime.Now.Ticks);
                r.Next();

                byte[] btColors = new byte[21];
                r.NextBytes(btColors);

                this.CurrentPlayer.HairColor = this.ceMainEditor.modelViewer.HairColor = Color.FromRgb(btColors[0], btColors[1], btColors[2]);
                this.CurrentPlayer.EyeColor = this.ceMainEditor.modelViewer.EyeColor = Color.FromRgb(btColors[3], btColors[4], btColors[5]);
                this.CurrentPlayer.PantsColor = this.ceMainEditor.modelViewer.PantsColor = Color.FromRgb(btColors[6], btColors[7], btColors[8]);
                this.CurrentPlayer.ShirtColor = this.ceMainEditor.modelViewer.ShirtColor = Color.FromRgb(btColors[9], btColors[10], btColors[11]);
                this.CurrentPlayer.ShoesColor = this.ceMainEditor.modelViewer.ShoesColor = Color.FromRgb(btColors[12], btColors[13], btColors[14]);
                this.CurrentPlayer.SkinColor = this.ceMainEditor.modelViewer.HandsColor = Color.FromRgb(btColors[15], btColors[16], btColors[17]);
                this.CurrentPlayer.SkinColor = this.ceMainEditor.modelViewer.HeadColor = Color.FromRgb(btColors[15], btColors[16], btColors[17]);
                this.CurrentPlayer.UnderShirtColor = this.ceMainEditor.modelViewer.UnderShirtColor = Color.FromRgb(btColors[18], btColors[19], btColors[20]);
            });

            // Attach click event to model image..
            this.ceMainEditor.modelViewer.MouseDown += new MouseButtonEventHandler((sender, e) =>
            {
                this.HairSelector.Visibility = Visibility.Visible;
            });
        }

        /// <summary>
        /// Gets or sets the current player being edited.
        /// </summary>
        public Player CurrentPlayer
        {
            get { return this.m_vCurrentPlayer; }
            set { this.m_vCurrentPlayer = value; this.DataContext = value; }
        }

        /// <summary>
        /// Menu handler to create a new profile.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mnuFile_New_Click(object sender, RoutedEventArgs e)
        {
            // Create new player instance..
            this.CurrentPlayer = new Player();

            // Reset the hair of the model viewer..
            this.CurrentPlayer.Hair = 0;
            this.ceMainEditor.modelViewer.HairFile = String.Format("Data\\Hair\\hair_{0}.png", this.CurrentPlayer.Hair);
        }

        /// <summary>
        /// Menu handler to open an existing Terraria profile file.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mnuFile_Open_Click(object sender, RoutedEventArgs e)
        {
            Microsoft.Win32.OpenFileDialog ofd = new Microsoft.Win32.OpenFileDialog();
            ofd.CheckFileExists = true;
            ofd.CheckPathExists = true;
            ofd.Filter = "Terraria Player File (*.plr)|*.plr";
            ofd.InitialDirectory = Terraria.PROFILE_PATH;
            ofd.Multiselect = false;
            ofd.Title = "Select a Terraria profile file..";
            ofd.ValidateNames = true;
            if (ofd.ShowDialog() ?? true)
            {
                try
                {
                    Player p = Terraria.Instance.LoadPlayer(ofd.FileName);
                    if (p != null)
                    {
                        this.CurrentPlayer = p;
                        this.CurrentPlayer.File = ofd.FileName;
                        this.ceMainEditor.modelViewer.HairFile = String.Format("Data\\Hair\\hair_{0}.png", p.Hair);
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("There was an exception caught while loading the selected player:\r\n\r\n" + ex.ToString(), "Error While Loading Player..", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
        }

        /// <summary>
        /// Menu handler to save an opened profile.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mnuFile_Save_Click(object sender, RoutedEventArgs e)
        {
            // Is this a previously opened file..
            if (this.CurrentPlayer.File == String.Empty)
            {
                mnuFile_SaveAs_Click(this, null);
            }
            else
            {
                // Attempt to save the file..
                bool bSaved = Terraria.Instance.SavePlayer(this.CurrentPlayer.File, this.CurrentPlayer);
                if (bSaved)
                {
                    MessageBox.Show("Profile was saved successfully!", "Success!", MessageBoxButton.OK, MessageBoxImage.Information);
                }
                else
                {
                    MessageBox.Show("Failed to save profile!", "Error!", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
        }

        /// <summary>
        /// Menu handler to save a profile file as the given file.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mnuFile_SaveAs_Click(object sender, RoutedEventArgs e)
        {
            Microsoft.Win32.SaveFileDialog sfd = new Microsoft.Win32.SaveFileDialog();
            sfd.CheckFileExists = false;
            sfd.CheckPathExists = true;
            sfd.Filter = "Terraria Player File (*.plr)|*.plr";
            sfd.InitialDirectory = Terraria.PROFILE_PATH;
            sfd.Title = "Save profile as..";
            sfd.ValidateNames = true;
            if (sfd.ShowDialog() ?? true)
            {
                bool bSaved = Terraria.Instance.SavePlayer(sfd.FileName, this.CurrentPlayer);
                if (bSaved)
                {
                    MessageBox.Show("Profile was saved successfully!", "Success!", MessageBoxButton.OK, MessageBoxImage.Information);
                }
                else
                {
                    MessageBox.Show("Failed to save profile!", "Error!", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
        }

        /// <summary>
        /// Menu handler to close this application.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mnuFile_Exit_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// Menu handler to open the about screen.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mnuAbout_Click(object sender, RoutedEventArgs e)
        {
            this.AboutScreen.Visibility = Visibility.Visible;
        }

        /// <summary>
        /// Handles updating the model hair after a user selection.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSelectHair_Click(object sender, RoutedEventArgs e)
        {
            var hairId = this.lstHairList.SelectedIndex;
            if (hairId > -1)
            {
                this.CurrentPlayer.Hair = hairId;
                this.ceMainEditor.modelViewer.HairFile = String.Format("Data\\Hair\\hair_{0}.png", hairId);
            }

            this.HairSelector.Visibility = Visibility.Collapsed;
        }

        /// <summary>
        /// Cancels the hair selector.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnCancelHair_Click(object sender, RoutedEventArgs e)
        {
            this.HairSelector.Visibility = Visibility.Collapsed;
        }

        /// <summary>
        /// Hyperlink navigation request handler.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
        {
            Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));
            e.Handled = true;
        }

        /// <summary>
        /// Closes the about screen.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnAboutClose_Click(object sender, RoutedEventArgs e)
        {
            this.AboutScreen.Visibility = Visibility.Collapsed;
        }
    }
}
